#!/usr/bin/env bash

set -euxo pipefail

temci exec --config ./scripts/bench/temci-config.yml >2
temci report --reporter codespeed2 |\
  sed 's/instructions:u/instructions/g' |\
  jq '(.build | to_entries | group_by(.key | test("~")) | map(from_entries)) as $groups | .build = $groups[0] | . + ($groups[1] | map_values({instructions: .}))'
  # sed: preserve old metric names
  # jq: move file metrics starting with "~" from "build" to toplevel and assign them the "instructions" metric

if [ -d .git ]; then
    DIR="$(git rev-parse @)"
    BASE_URL="https://speed.lean-lang.org/mathlib4-out/$DIR"
    {
        cat <<EOF
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Lakeprof Report</title>
</head>
<h1>Lakeprof Report</h1>

<p>This is an automated build time analysis generated by <a href="https://github.com/Kha/lakeprof">lakeprof</a> for <a href="https://github.com/leanprover-community/mathlib4/commit/$DIR">mathlib4/$(git rev-parse --short @)</a>.</p>

<p>The underlying data is the <em>build trace</em>, which is a recording of the start time and duration of each module build.
You can open a visualization of it here to observe the build parallelism of the project on the benchmarking machine:</p>

<button type="button" id="btn_fetch">View build trace in Perfetto</button>
EOF

      cat <<'EOF'
<script type="text/javascript">
const ORIGIN = 'https://ui.perfetto.dev';

const btnFetch = document.getElementById('btn_fetch');

async function fetchAndOpen(traceUrl) {
  const resp = await fetch(traceUrl);
  // Error checking is left as an exercise to the reader.
  const blob = await resp.blob();
  const arrayBuffer = await blob.arrayBuffer();
  openTrace(arrayBuffer, traceUrl);
}

function openTrace(arrayBuffer, traceUrl) {
  const win = window.open(ORIGIN);
  if (!win) {
    btnFetch.style.background = '#f3ca63';
  	btnFetch.onclick = () => openTrace(arrayBuffer);
    btnFetch.innerText = 'Popups blocked, click here to open the trace file';
    return;
  }

  const timer = setInterval(() => win.postMessage('PING', ORIGIN), 50);

  const onMessageHandler = (evt) => {
    if (evt.data !== 'PONG') return;

    // We got a PONG, the UI is ready.
    window.clearInterval(timer);
    window.removeEventListener('message', onMessageHandler);

    const reopenUrl = new URL(location.href);
    reopenUrl.hash = `#reopen=${traceUrl}`;
    win.postMessage({
      perfetto: {
        buffer: arrayBuffer,
        title: 'Lake Build Trace',
        url: reopenUrl.toString(),
    }}, ORIGIN);
  };

  window.addEventListener('message', onMessageHandler);
}

// This is triggered when following the link from the Perfetto UI's sidebar.
if (location.hash.startsWith('#reopen=')) {
 const traceUrl = location.hash.substr(8);
 fetchAndOpen(traceUrl);
}
EOF
        cat <<EOF
btnFetch.onclick = () => fetchAndOpen("$BASE_URL/lakeprof.trace_event");
</script>

<p>The <em>critical path</em> is the chain of dependent modules with the maximum cumulative build time, i.e. the path through the project determining total build time assuming unlimited parallelism.
In practice, you may see gaps in its visualization above when the concrete degree of parallelism on the benchmarking machine is insufficient.
The following table lists the critical path in detail including individual and cumulative absolute and relative timings.</p>

<pre><code>
$(lakeprof report -p)
</code></pre>

<p>The <em>rebuild critical path</em> is a variant of the critical path that excludes private import edges when using the module system.
Thus it may be shorter and is a better indicator of the worst-case build time when a previous version of the project has already been built and a single-file change is made.</p>

<pre><code>
$(lakeprof report -r)
</code></pre>

</body></html>
EOF
    } | tee index.html

    curl -T index.html $BASE_URL/index.html
    curl -T lakeprof.log $BASE_URL/lakeprof.log
    lakeprof report -c
    curl -T lakeprof.trace_event $BASE_URL/lakeprof.trace_event
fi
